#include "stdafx.h"
#include "msg/taskmanager.hpp"
#include "msg/tasknotification.hpp"

namespace JHCPP
{
	namespace msg
	{
		const int CTaskManager::MIN_PROGRESS_NOTIFICATION_INTERVAL = 100000; // 100 milliseconds
		
		CTaskManager::CTaskManager() : m_threadPool(CThreadPool::defaultPool())
		{
		}

		CTaskManager::CTaskManager(CThreadPool& pool) : m_threadPool(pool)
		{
		}

		CTaskManager::~CTaskManager()
		{
		}

		void CTaskManager::start(CTask* pTask)
		{
			TaskPtr pAutoTask(pTask); // take ownership immediately
			CMutex::ScopedLock lock(m_mutex);

			pAutoTask->setOwner(this);
			pAutoTask->setState(CTask::TASK_STARTING);
			m_taskList.push_back(pAutoTask);
			try
			{
				m_threadPool.start(*pAutoTask, pAutoTask->name());
			}
			catch (...)
			{
				m_taskList.pop_back();
				throw;
			}
		}

		void CTaskManager::cancelAll()
		{
			CMutex::ScopedLock lock(m_mutex);

			for (TaskList::iterator it = m_taskList.begin(); it != m_taskList.end(); ++it)
			{
				(*it)->cancel();
			}
		}

		void CTaskManager::joinAll()
		{
			m_threadPool.joinAll();
		}

		CTaskManager::TaskList CTaskManager::taskList() const
		{
			CMutex::ScopedLock lock(m_mutex);

			return m_taskList;
		}

		void CTaskManager::addObserver(const CAbstractObserver& observer)
		{
			m_nc.addObserver(observer);
		}

		void CTaskManager::removeObserver(const CAbstractObserver& observer)
		{
			m_nc.removeObserver(observer);
		}

		void CTaskManager::postNotification(const CNotification::Ptr& pNf)
		{
			m_nc.postNotification(pNf);
		}

		void CTaskManager::taskStarted(CTask* pTask)
		{
			m_nc.postNotification(new CTaskStartedNotification(pTask));
		}

		void CTaskManager::taskProgress(CTask* pTask, float progress)
		{
			CMutex::ScopedLock lock(m_mutex);

			if (m_lastProgressNotification.isElapsed(MIN_PROGRESS_NOTIFICATION_INTERVAL))
			{
				m_lastProgressNotification.update();
				m_nc.postNotification(new CTaskProgressNotification(pTask, progress));
			}
		}

		void CTaskManager::taskCancelled(CTask* pTask)
		{
			m_nc.postNotification(new CTaskCancelledNotification(pTask));
		}

		void CTaskManager::taskFinished(CTask* pTask)
		{
			m_nc.postNotification(new CTaskFinishedNotification(pTask));

			CMutex::ScopedLock lock(m_mutex);
			for (TaskList::iterator it = m_taskList.begin(); it != m_taskList.end(); ++it)
			{
				if (*it == pTask)
				{
					m_taskList.erase(it);
					break;
				}
			}
		}

		void CTaskManager::taskFailed(CTask* pTask, const CException& exc)
		{
			m_nc.postNotification(new CTaskFailedNotification(pTask, exc));
		}
	}//end of namespace JHCPP
}//end of namespace msg
